 /* Copyright (c) 2007 Pentaho Corporation.  All rights reserved. 
 * This software was developed by Pentaho Corporation and is provided under the terms 
 * of the GNU Lesser General Public License, Version 2.1. You may not use 
 * this file except in compliance with the license. If you need a copy of the license, 
 * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is Pentaho 
 * Data Integration.  The Initial Developer is Pentaho Corporation.
 *
 * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" 
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to 
 * the license for the specific language governing your rights and limitations.*/

 

package org.pentaho.di.ui.spoon.wizards;

import java.util.Hashtable;
import java.util.StringTokenizer;

import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.database.Database;
import org.pentaho.di.core.exception.KettleDatabaseException;
import org.pentaho.di.ui.core.PropsUI;
import org.pentaho.di.ui.core.dialog.ErrorDialog;



/**
 * This wizard page let's you select the tables that need to be ripped.
 * 
 * @author Matt
 * @since 17-apr-04
 *
 */
public class RipDatabaseWizardPage2 extends WizardPage
{
	private PropsUI props;
	 
	private String    input[];
	
	private Hashtable<Integer,String> selection;
	
	private Shell     shell;
	private List      wListSource, wListDest;
	private Label     wlListSource, wlListDest;
	
	private Button    wAddOne, wAddAll, wRemoveAll, wRemoveOne;
    
	public RipDatabaseWizardPage2(String arg)
	{
		super(arg);
		this.props=PropsUI.getInstance();

		selection = new Hashtable<Integer,String>();

		setTitle("Select the tables");
		setDescription("Select the tables to rip from the source database");
	}
	
	public void createControl(Composite parent)
	{
		shell   = parent.getShell();

		int margin  = Const.MARGIN;		
		
		// create the composite to hold the widgets
		Composite composite = new Composite(parent, SWT.NONE);
        props.setLook(composite);
	    
	    FormLayout compLayout = new FormLayout();
	    compLayout.marginHeight = Const.FORM_MARGIN;
	    compLayout.marginWidth  = Const.FORM_MARGIN;
		composite.setLayout(compLayout);

		// Put it all on the composite!
		////////////////////////////////////////////////////
		// Top & Bottom regions.
		////////////////////////////////////////////////////
		Composite top    = new Composite(composite, SWT.NONE);
		FormLayout topLayout = new FormLayout();
		topLayout.marginHeight = margin;
		topLayout.marginWidth  = margin;
		top.setLayout(topLayout);
		
		FormData fdTop  = new FormData(); 
		fdTop.left   = new FormAttachment(0, 0);
		fdTop.top    = new FormAttachment(0, 0);
		fdTop.right  = new FormAttachment(100, 0);
		fdTop.bottom = new FormAttachment(100, -50);
		top.setLayoutData(fdTop);
        props.setLook(top);
		
		Composite bottom = new Composite(composite, SWT.NONE);
		bottom.setLayout(new FormLayout());
		FormData fdBottom = new FormData(); 
		fdBottom.left   = new FormAttachment(0, 0); 
		fdBottom.top    = new FormAttachment(top, 0);
		fdBottom.right  = new FormAttachment(100, 0);
		fdBottom.bottom = new FormAttachment(100, 0);
		bottom.setLayoutData(fdBottom);
		props.setLook(bottom);

		
		////////////////////////////////////////////////////
		// Sashform
		////////////////////////////////////////////////////
		
		SashForm sashform = new SashForm(top, SWT.HORIZONTAL); 
		sashform.setLayout(new FormLayout());
		FormData fdSashform = new FormData(); 
		fdSashform.left   = new FormAttachment(0, 0); 
		fdSashform.top    = new FormAttachment(0, 0);
		fdSashform.right  = new FormAttachment(100, 0);
		fdSashform.bottom = new FormAttachment(100, 0);
		sashform.setLayoutData(fdSashform);

		//////////////////////////
		/// LEFT
		//////////////////////////
		Composite leftsplit = new Composite(sashform, SWT.NONE);
		leftsplit.setLayout(new FormLayout());
		FormData fdLeftsplit = new FormData(); 
		fdLeftsplit.left   = new FormAttachment(0, 0); 
		fdLeftsplit.top    = new FormAttachment(0, 0);
		fdLeftsplit.right  = new FormAttachment(100, 0);
		fdLeftsplit.bottom = new FormAttachment(100, 0);
		leftsplit.setLayoutData(fdLeftsplit);
        props.setLook(leftsplit);

 		// Source list to the left...
		wlListSource  = new Label(leftsplit, SWT.NONE);
		wlListSource.setText("Available items:");
        props.setLook(wlListSource);

 		FormData fdlListSource = new FormData();
		fdlListSource.left   = new FormAttachment(0, 0); 
		fdlListSource.top    = new FormAttachment(0, 0);
		wlListSource.setLayoutData(fdlListSource);
		
 		wListSource = new List(leftsplit, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
        props.setLook(wListSource);

 		FormData fdListSource = new FormData();
		fdListSource.left   = new FormAttachment(0, 0); 
		fdListSource.top    = new FormAttachment(wlListSource, 0);
		fdListSource.right  = new FormAttachment(100, 0);
		fdListSource.bottom = new FormAttachment(100, 0);
		wListSource.setLayoutData(fdListSource);
 		
 		///////////////////////////
 		// MIDDLE
 		///////////////////////////
 		
		Composite compmiddle = new Composite(sashform, SWT.NONE);
		compmiddle.setLayout (new FormLayout());
 		FormData fdCompMiddle = new FormData();
		fdCompMiddle.left   = new FormAttachment(0, 0); 
		fdCompMiddle.top    = new FormAttachment(0, 0);
		fdCompMiddle.right  = new FormAttachment(100, 0);
		fdCompMiddle.bottom = new FormAttachment(100, 0);
		compmiddle.setLayoutData(fdCompMiddle);
        props.setLook(compmiddle);

		wAddOne    = new Button(compmiddle, SWT.PUSH); wAddOne   .setText(" > ");  wAddOne   .setToolTipText("Add the selected items on the left.");
		wAddAll    = new Button(compmiddle, SWT.PUSH); wAddAll   .setText(" >> "); wAddAll   .setToolTipText("Add all items on the left.");
		wRemoveOne = new Button(compmiddle, SWT.PUSH); wRemoveOne.setText(" < ");  wRemoveOne.setToolTipText("Remove the selected items on the right.");
		wRemoveAll = new Button(compmiddle, SWT.PUSH); wRemoveAll.setText(" << "); wRemoveAll.setToolTipText("Add all items on the right.");

		FormData fdAddOne = new FormData();
		fdAddOne.left   = new FormAttachment(compmiddle, 0, SWT.CENTER); 
		fdAddOne.top    = new FormAttachment(30, 0);
		wAddOne.setLayoutData(fdAddOne);

		FormData fdAddAll = new FormData();
		fdAddAll.left   = new FormAttachment(compmiddle, 0, SWT.CENTER);
		fdAddAll.top    = new FormAttachment(wAddOne, margin);
		wAddAll.setLayoutData(fdAddAll);

		FormData fdRemoveAll = new FormData();
		fdRemoveAll.left   = new FormAttachment(compmiddle, 0, SWT.CENTER);
		fdRemoveAll.top    = new FormAttachment(wAddAll, margin);
		wRemoveAll.setLayoutData(fdRemoveAll);

		FormData fdRemoveOne = new FormData();
		fdRemoveOne.left   = new FormAttachment(compmiddle, 0, SWT.CENTER);
		fdRemoveOne.top    = new FormAttachment(wRemoveAll, margin);
		wRemoveOne.setLayoutData(fdRemoveOne);


		/////////////////////////////////
		// RIGHT
		/////////////////////////////////
		
		Composite rightsplit = new Composite(sashform, SWT.NONE);
		rightsplit.setLayout(new FormLayout());
		FormData fdRightsplit = new FormData(); 
		fdRightsplit .left   = new FormAttachment(0, 0); 
		fdRightsplit .top    = new FormAttachment(0, 0);
		fdRightsplit .right  = new FormAttachment(100, 0);
		fdRightsplit .bottom = new FormAttachment(100, 0);
		rightsplit.setLayoutData(fdRightsplit );
        props.setLook(rightsplit);

		wlListDest = new Label(rightsplit, SWT.NONE);
		wlListDest.setText("Your selection:");
        props.setLook(wlListDest);

 		FormData fdlListDest = new FormData();
		fdlListDest.left   = new FormAttachment(0, 0); 
		fdlListDest.top    = new FormAttachment(0, 0);
		wlListDest.setLayoutData(fdlListDest);

		wListDest = new List(rightsplit, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
        props.setLook(wListDest);

		FormData fdListDest = new FormData(); 
		fdListDest .left   = new FormAttachment(0, 0); 
		fdListDest .top    = new FormAttachment(wlListDest, 0);
		fdListDest .right  = new FormAttachment(100, 0);
		fdListDest .bottom = new FormAttachment(100, 0);
		wListDest.setLayoutData(fdListDest );

		sashform.setWeights(new int[] { 45, 10, 45 });

		// Drag & Drop for steps
		Transfer[] ttypes = new Transfer[] {TextTransfer.getInstance() };
		
		DragSource ddSource = new DragSource(wListSource, DND.DROP_MOVE | DND.DROP_COPY);
		ddSource.setTransfer(ttypes);
		ddSource.addDragListener(new DragSourceListener() 
			{
				public void dragStart(DragSourceEvent event){ }
	
				public void dragSetData(DragSourceEvent event) 
				{
					String ti[] = wListSource.getSelection();
					String data = new String();
					for (int i=0;i<ti.length;i++) data+=ti[i]+Const.CR;
					event.data = data;
				}
	
				public void dragFinished(DragSourceEvent event) {}
			}
		);
		DropTarget ddTarget = new DropTarget(wListDest, DND.DROP_MOVE | DND.DROP_COPY);
		ddTarget.setTransfer(ttypes);
		ddTarget.addDropListener(new DropTargetListener() 
		{
			public void dragEnter(DropTargetEvent event) { }
			public void dragLeave(DropTargetEvent event) { }
			public void dragOperationChanged(DropTargetEvent event) { }
			public void dragOver(DropTargetEvent event) { }
			public void drop(DropTargetEvent event) 
			{
				if (event.data == null) { // no data to copy, indicate failure in event.detail
					event.detail = DND.DROP_NONE;
					return;
				}
				StringTokenizer strtok = new StringTokenizer((String)event.data, Const.CR);
				while (strtok.hasMoreTokens())
				{
					String   source = strtok.nextToken();
					addToDestination(source);
				}
			}

			public void dropAccept(DropTargetEvent event) 
			{
			}
		});

		wListSource.addKeyListener(new KeyAdapter()
		{
			public void keyPressed(KeyEvent e)
			{
				if (e.character==SWT.CR)
				{
					addToSelection(wListSource.getSelection());
				}
			}
		});
		wListDest.addKeyListener(new KeyAdapter()
			{
				public void keyPressed(KeyEvent e)
				{
					if (e.character==SWT.CR)
					{
						delFromSelection(wListDest.getSelection());
					}
				}
			});

		// Double click adds to destination.
		wListSource.addSelectionListener(new SelectionAdapter()
			{
				public void widgetDefaultSelected(SelectionEvent e)
				{
					addToSelection(wListSource.getSelection());
				}
			}
		);
		// Double click adds to source
		wListDest.addSelectionListener(new SelectionAdapter()
			{
				public void widgetDefaultSelected(SelectionEvent e)
				{
					String sel[] = wListDest.getSelection();
					delFromSelection(sel);
				}
			}
		);

		wAddOne.addSelectionListener(new SelectionAdapter()
			{
				public void widgetSelected(SelectionEvent e)
				{
					addToSelection(wListSource.getSelection());
				}
			}
		);

		wRemoveOne.addSelectionListener(new SelectionAdapter()
										{
											public void widgetSelected(SelectionEvent e)
											{
												delFromSelection(wListDest.getSelection());
											}
										}
									);

		wAddAll.addSelectionListener(new SelectionAdapter()
										{
											public void widgetSelected(SelectionEvent e)
											{
												addAllToSelection();
											}
										}
									);

		wRemoveAll.addSelectionListener(new SelectionAdapter()
										{
											public void widgetSelected(SelectionEvent e)
											{
												removeAllFromSelection();
											}
										}
									);
		
		// set the composite as the control for this page
		setControl(composite);
	}	
	
	public boolean getInputData()
	{
		// Get some data...
		RipDatabaseWizardPage1 page1 = (RipDatabaseWizardPage1)getPreviousPage();
		
		Database sourceDb = new Database(RipDatabaseWizard.loggingObject, page1.getSourceDatabase());
		try
		{
			sourceDb.connect();
			input = sourceDb.getTablenames(false); // Don't include the schema since it can cause invalid syntax
		}
		catch(KettleDatabaseException dbe)
		{
			new ErrorDialog(shell, "Error getting tables", "Error obtaining table list from database!", dbe);
			input = null;
			return false;
		}
		finally
		{
			sourceDb.disconnect();
		}
		return true;
	}
	
	public void getData()
	{
		wListSource.removeAll();
		wListDest.removeAll();
		
		if (input!=null)
		{
			for (int i=0;i<input.length;i++)
			{
				Integer idx = Integer.valueOf(i);
				String str = selection.get(idx);
				if (str==null) // Not selected: show in source!
				{
					wListSource.add(input[i]);
				}
				else // Selected, show in destination!
				{
					wListDest.add(input[i]);
				}
			}
		}
		setPageComplete(canFlipToNextPage());
	}
	
	public void addAllToSelection()
	{
		// Just remove it all from both lists
		// Then add input[] to the destination list...
		// This is much faster.
		wListSource.removeAll();
		wListDest.removeAll();
		selection.clear();
		for (int i=0;i<input.length;i++) 
		{
			wListDest.add(input[i]);
			selection.put(Integer.valueOf(i), input[i]);
		}
		
		setPageComplete(canFlipToNextPage());
	}
	
	public void removeAllFromSelection()
	{
		// Just remove it all from both lists
		// Then add input[] to the source list...
		// This is much faster.
		wListSource.removeAll();
		wListDest.removeAll();
		selection.clear();
		for (int i=0;i<input.length;i++) wListSource.add(input[i]);
		
		setPageComplete(canFlipToNextPage());
	}
	
	
	
	public void addToSelection(String string[])
	{
		for (int i=0;i<string.length;i++) addToDestination(string[i]);
		setPageComplete(canFlipToNextPage());
	}

	public void delFromSelection(String string[])
	{
		for (int i=0;i<string.length;i++) delFromDestination(string[i]);
		setPageComplete(canFlipToNextPage());
	}

	public void addToDestination(String string)
	{
		int idxInput = Const.indexOfString(string, input);
		selection.put(Integer.valueOf(idxInput), string);
		
		getData();
	}

	public void delFromDestination(String string)
	{
		int idxInput = Const.indexOfString(string, input);
		selection.remove(Integer.valueOf(idxInput));
		
		getData();
	}
	
	public boolean canFlipToNextPage()
	{
		boolean canFlip = wListDest.getItemCount()>0;
		// System.out.println("canflip = "+canFlip);
		return canFlip;
	}	
	
	public String[] getSelection()
	{
		return wListDest.getItems();
	}
}
